feat: Add client request duration metric.#4132
Conversation
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a new client request duration metric, Highlights
Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces a new metric for client request duration, gcp.client.request.duration, implemented through a new GoldenTelemetryMetricsTracer. The changes also include a valuable refactoring that centralizes utility methods like extractStatus and toOtelAttributes into a new ObservabilityUtils class, improving code organization. The new functionality is well-tested. My review includes a couple of suggestions to improve robustness and error handling in the new tracer and its factory, which are still valid. Overall, this is a solid contribution.
| public ApiTracer newTracer(ApiTracer parent, SpanName spanName, OperationType operationType) { | ||
| return new GoldenTelemetryMetricsTracer(openTelemetry, apiTracerContext); | ||
| } |
There was a problem hiding this comment.
The apiTracerContext field is not initialized in the constructor and can be null if newTracer is called before withContext. This would lead to a NullPointerException when apiTracerContext.libraryMetadata() is called inside the GoldenTelemetryMetricsTracer constructor. To make the factory more robust against misuse, please add a null-check for apiTracerContext and throw an IllegalStateException if it hasn't been set.
public ApiTracer newTracer(ApiTracer parent, SpanName spanName, OperationType operationType) {
if (apiTracerContext == null) {
throw new IllegalStateException(
"ApiTracerContext has not been set. Call withContext() before creating a new tracer.");
}
return new GoldenTelemetryMetricsTracer(openTelemetry, apiTracerContext);
}References
- Explicit
ifchecks for null handling are preferred for better readability in simple cases, aligning with the preference overjava.util.Optionalfor such scenarios.
There was a problem hiding this comment.
I think this should not happen with the current setup but +1 for the extra safety "against misuse" a null check brings.
| @Override | ||
| public void operationSucceeded() { | ||
| if (clientRequestFinished.getAndSet(true)) { | ||
| throw new IllegalStateException(); |
There was a problem hiding this comment.
For better diagnostics, the IllegalStateException should include a descriptive message, for example: "Operation has already been completed". This feedback also applies to the exceptions thrown in operationCancelled() (line 92) and operationFailed() (line 102). Consider defining this message as a shared constant for reuse.
| throw new IllegalStateException(); | |
| throw new IllegalStateException("Operation has already been completed"); |
diegomarquezp
left a comment
There was a problem hiding this comment.
Thanks for the PR.
external/com_google_api_gax_java/gax/src/test/java/com/google/api/gax/tracing/GoldenSignalMetricsTracerTest.java:59: error: cannot find symbol
private InMemoryMetricReader metricReader;
^
symbol: class InMemoryMetricReader
location: class GoldenSignalMetricsTracerTest
external/com_google_api_gax_java/gax/src/test/java/com/google/api/gax/tracing/GoldenSignalMetricsTracerTest.java:133: error: cannot find symbol
private void verifyMetricDataContainsMeterInfo(MetricData metricData) {
I think we need to add an entry to gax-java/dependencies.properties and related BUILD files.
gax-java/gax/src/main/java/com/google/api/gax/tracing/GoldenSignalMetricsTracer.java
Outdated
Show resolved
Hide resolved
gax-java/gax/src/main/java/com/google/api/gax/tracing/GoldenSignalMetricsTracer.java
Outdated
Show resolved
Hide resolved
gax-java/gax/src/main/java/com/google/api/gax/tracing/GoldenSignalMetricsTracer.java
Outdated
Show resolved
Hide resolved
| public ApiTracer newTracer(ApiTracer parent, SpanName spanName, OperationType operationType) { | ||
| return new GoldenTelemetryMetricsTracer(openTelemetry, apiTracerContext); | ||
| } |
There was a problem hiding this comment.
I think this should not happen with the current setup but +1 for the extra safety "against misuse" a null check brings.
gax-java/gax/src/test/java/com/google/api/gax/tracing/GoldenSignalMetricsTracerTest.java
Outdated
Show resolved
Hide resolved
gax-java/gax/src/main/java/com/google/api/gax/tracing/GoldenSignalsMetricsTracer.java
Show resolved
Hide resolved
gax-java/gax/src/main/java/com/google/api/gax/tracing/GoldenSignalMetricsTracer.java
Outdated
Show resolved
Hide resolved
gax-java/gax/src/main/java/com/google/api/gax/tracing/GoldenSignalMetricsTracer.java
Outdated
Show resolved
Hide resolved
|
|
||
| @Override | ||
| public ApiTracer newTracer(ApiTracer parent, SpanName spanName, OperationType operationType) { | ||
| return new GoldenSignalMetricsTracer(openTelemetry, apiTracerContext); |
There was a problem hiding this comment.
Where do we capture things like rpc.method?
There was a problem hiding this comment.
It will be populated in apiTracerContext. Then the tracer will get it from apiTracerContext and record it.
| this.metricsRecorder = metricsRecorder; | ||
| } | ||
|
|
||
| @Override |
There was a problem hiding this comment.
Add more doc that "Operation" is actually "Client Request" in the context of golden signal metrics.
gax-java/gax/src/main/java/com/google/api/gax/tracing/GoldenSignalMetricsTracer.java
Outdated
Show resolved
Hide resolved
gax-java/gax/src/main/java/com/google/api/gax/tracing/GoldenSignalMetricsTracer.java
Outdated
Show resolved
Hide resolved
gax-java/gax/src/main/java/com/google/api/gax/tracing/GoldenSignalMetricsTracer.java
Outdated
Show resolved
Hide resolved
westarle
left a comment
There was a problem hiding this comment.
LGTM but I think you should get an approval from the Java team.
we should get a review from a java team member.
|
|
There was a problem hiding this comment.
LGTM overall. One more comment.
Looking for your opinion on the following:
ITOtelMetrics aims for end-to-end (emulated) testing for the old MetricsTracer + related calsses.
What if we add a new IT for golden signal metrics? Maybe not as extensive as ITOtelMetrics but just a few sanity checks such as in ITOtelTracing
Yes I do plan to do it. I think it's better to be a separate PR since it is integration tests. |
diegomarquezp
left a comment
There was a problem hiding this comment.
Yes I do plan to do it. I think it's better to be a separate PR since it is integration tests.
SGTM





This PR adds basic implementation for client request duration metric.
The following attributes are also added:
The overall design follows
ApiTracer/ApiTracerFactorypattern, createsGoldenSignalMetricsTracer/GoldenSignalMetricsTracerFactorythat implement ApiTracer/ApiTracerFactory respectively.GoldenSignalMetricsTracerFactoryis expected to be passed in during client initialization.GoldenSignalMetricsTracertracks the lifecycle of a request and calculates the duration of client requests.